package cn.mesmile.shiro.utils;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTCreationException;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.extern.slf4j.Slf4j;

import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;

@Slf4j
public class JwtUtil {

    private JwtUtil(){}

    //JWT-account
    public static final String ACCOUNT = "username";
    //JWT-currentTimeMillis
    public final static String CURRENT_TIME_MILLIS = "currentTimeMillis";
    //有效期时间2小时
    public static final long EXPIRE_TIME = 2 * 60 * 60 * 1000L;
    //秘钥
    public static final String SECRET_KEY = "shirokey";
    // 发行者
    public static final String ISSUER = "mesmile";
    // 认证头   X-Authorization-With
    public static final String AUTH_HEADER = "Authorization";



    /**
     * 生成签名返回token
     *
     * @param account
     * @param currentTimeMillis
     * @return
     */
    public static String sign(String account, long currentTimeMillis) {
        // 帐号加JWT私钥加密
        String secret = account + SECRET_KEY;
        // 此处过期时间，单位：毫秒，在当前时间到后边的2小时内都是有效的
        Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
        //采用HMAC256加密
        Algorithm algorithm = Algorithm.HMAC256(secret);

        return JWT.create()
                .withIssuer(ISSUER)
                .withClaim(ACCOUNT, account)
                .withClaim(CURRENT_TIME_MILLIS, currentTimeMillis)
                .withExpiresAt(date)
                //创建一个新的JWT，并使用给定的算法进行标记
                .sign(algorithm);
    }

    /**
     * 校验token是否正确
     *
     * @param token
     * @return
     */
    public static boolean verify(String token) {
        String secret = getClaim(token, ACCOUNT) + SECRET_KEY;
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTVerifier verifier = JWT.require(algorithm).build();
        verifier.verify(token);
        return true;
    }

    /**
     * 获得Token中的信息无需secret解密也能获得
     * 获取token 中的 用户名
     * @param token
     * @param claim
     * @return
     */
    public static String getClaim(String token, String claim) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(claim).asString();
        } catch (JWTDecodeException e) {
            log.error(">>>>>>>>> 获取用户名失败： {}", e.getMessage());
            return null;
        }
    }

    /**
     * 获取 token的签发时间
     */
    public static Date getIssuedAt(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getIssuedAt();
        } catch (JWTDecodeException e) {
            log.error(">>>>>>>>> 获取用户名失败： {}", e.getMessage());
            return null;
        }
    }

    /**
     * 验证 token是否过期
     */
    public static boolean isTokenExpired(String token) {
        Date now = Calendar.getInstance().getTime();
        DecodedJWT jwt = JWT.decode(token);
        return jwt.getExpiresAt().before(now);
    }

    /**
     * 刷新 token的过期时间
     */
    public static String refreshTokenExpired(String token) {
        String secret = getClaim(token, ACCOUNT) + SECRET_KEY;

        DecodedJWT jwt = JWT.decode(token);
        Map<String, Claim> claims = jwt.getClaims();
        try {
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
            Algorithm algorithm = Algorithm.HMAC256(secret);
            JWTCreator.Builder builer = JWT.create().withExpiresAt(date);
            for (Map.Entry<String, Claim> entry : claims.entrySet()) {
                builer.withClaim(entry.getKey(), entry.getValue().asString());
            }
            return builer.sign(algorithm);
        } catch (JWTCreationException e) {
            return null;
        }
    }




    public static void main(String[] args) {
        //
        // nEjV5Y-dqAR3EIpzcaqzjcfzt58pidCO2zk4GQQnhq8
        String jack = sign("jack", System.currentTimeMillis());
        System.out.println("jack = " + jack);


        System.out.println("verify(jack) = " + verify(jack));

        DecodedJWT jwt = JWT.decode("eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MTM5MjMzOTIsInVzZXJfbmFtZSI6InpoZW5nYmluQGFvc3NjaS5jb20iLCJhdXRob3JpdGllcyI6WyJVc2VyQ29kZT0zYThiM2E3OGMzNjU0NjI0YmU2MGY1NmZkOTlmMTU2YiIsIlVzZXJJbmZvPTNhOGIzYTc4YzM2NTQ2MjRiZTYwZjU2ZmQ5OWYxNTZiI3poZW5nYmluQGFvc3NjaS5jb20jbnVsbCPpg5HlhbUjYW9zc2NpIl0sImp0aSI6IjVkN2FhYWYwLTcyODctNGFhMC1iMDZkLWEwMzA2ZGY2YTc0MSIsImNsaWVudF9pZCI6IndlYkFwcCIsInNjb3BlIjpbIndlYiJdfQ.bRJM4kEcUz1LtpkSuKZZ857o713rlkTZs2l0vMMsU-M");
        Map<String, Claim> claims = jwt.getClaims();
        Iterator<Map.Entry<String, Claim>> iterator =
                claims.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Claim> next = iterator.next();
            String key = next.getKey();
            Claim value = next.getValue();
            System.out.println("value.asString() = " + value.asString());
        }


    }


}
